package com.bolt.report.definition;

import com.bolt.common.collection.IteratorUtil;
import com.bolt.common.utils.StrUtil;
import com.bolt.core.view.components.Form;
import com.bolt.core.view.components.FormItem;
import com.bolt.report.engine.fill.FillContext;

import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

public class ReportDefinition implements Serializable {

    private String id;

    private String reportFullName;

    private String desc;

    private Class<?> springDataProvider;

    private PaperDefinition paper;

    private List<RowDefinition> title;

    private List<RowDefinition> summary;

    private List<RowDefinition> elements;

    private List<RowDefinition> heads;

    private List<RowDefinition> groupSummary;

    private Set<SortDefinition> sortDefinitions;

    private List<Integer> columnDefinition;

    private List<DataSetDefinition> dataSetDefinitions;

    private Form queryForm;

    private boolean loopPrintTitle = false;

    private boolean loopPrintHead = false;

    private boolean ignorePagination = false;


    public ReportDefinition() {
        this.title = new ArrayList<>();
        this.heads = new ArrayList<>();
        this.elements = new ArrayList<>();
        this.summary = new ArrayList<>();
        this.groupSummary = new ArrayList<>();
    }

    public String getReportFullName() {
        return reportFullName;
    }

    public void setReportFullName(String reportFullName) {
        this.reportFullName = reportFullName;
    }

    public PaperDefinition getPaper() {
        return paper;
    }

    public void setPaper(PaperDefinition paper) {
        this.paper = paper;
    }


    public List<RowDefinition> getElements() {
        return elements;
    }

    public CellDefinition getElement(String name) {
        CellDefinition cellDefinition = null;
        for (RowDefinition rowElements : elements) {
            for (CellDefinition element : rowElements.getCellDefinitions()) {
                if (StrUtil.equalsIgnoreCase(element.getName(), name)) {
                    cellDefinition = element;
                    break;
                }
            }
        }
        return cellDefinition;
    }

    public int getElementIndex(String name) {
        CellDefinition cellDefinition = getElement(name);
        return cellDefinition.getX();
    }

    public List<RowDefinition> getTitle() {
        return title;
    }

    public void setTitle(List<RowDefinition> title) {
        this.title = title;
    }

    public List<RowDefinition> getSummary() {
        return summary;
    }

    public void setSummary(List<RowDefinition> summary) {
        this.summary = summary;
    }

    public void setElements(List<RowDefinition> elements) {
        this.elements = elements;
    }

    public void setHeads(List<RowDefinition> heads) {
        this.heads = heads;
    }

    public Set<SortDefinition> getSortDefinitions() {
        return sortDefinitions;
    }

    public void setSortDefinitions(Set<SortDefinition> sortDefinitions) {
        this.sortDefinitions = sortDefinitions;
    }


    public Class<?> getSpringDataProvider() {
        return springDataProvider;
    }

    public void setSpringDataProvider(Class<?> springDataProvider) {
        this.springDataProvider = springDataProvider;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    public List<Integer> getColumnDefinition() {
        return columnDefinition;
    }

    public void setColumnDefinition(List<Integer> columnDefinition) {
        this.columnDefinition = columnDefinition;
    }

    public List<DataSetDefinition> getDataSetDefinitions() {
        return dataSetDefinitions;
    }

    public void setDataSetDefinitions(List<DataSetDefinition> dataSetDefinitions) {
        this.dataSetDefinitions = dataSetDefinitions;
    }

    public Set<String> getAllDataSetCode() {
        Set<String> allCodeSet = new HashSet();
        for (RowDefinition rowElements : elements) {
            Set<String> code = rowElements.getCellDefinitions().stream()
                    .filter(k -> k.getElementType() == ElementType.DATASET)
                    .map(k -> k.getKey())
                    .collect(Collectors.toSet());
            allCodeSet.addAll(code);
        }
        return allCodeSet;
    }

    public Map<String, List<CellDefinition>> getDataSetMap(List<CellDefinition> cellDefinitions, FillContext context) {
        return cellDefinitions.stream().filter(k -> (!k.isDataSetCell(context)) && !k.isGroup() && StrUtil.isNotBlank(k.getKey()))
                .collect(Collectors.groupingBy(CellDefinition::getKey));
    }

    public List<CellDefinition> getDataSetCell(List<CellDefinition> cellDefinitions) {
        return cellDefinitions.stream().filter(k -> k.getElementType() == ElementType.DATASET && !k.isGroup())
                .collect(Collectors.toList());
    }

    public List<CellDefinition> getRowCell(List<CellDefinition> cellDefinitions) {
        return cellDefinitions.stream().filter(k -> !k.isGroup())
                .collect(Collectors.toList());
    }


    public List<CellDefinition> getStaticCell(List<CellDefinition> cellDefinitions, FillContext context) {
        return cellDefinitions.stream().filter(k -> k.isDataSetCell(context)).collect(Collectors.toList());
    }

    public List<CellDefinition> getChartCell(List<CellDefinition> cellDefinitions) {
        return cellDefinitions.stream().filter(k -> k.getElementType() == ElementType.CHART)
                .collect(Collectors.toList());
    }

    public List<CellDefinition> getGroupCell(List<CellDefinition> cellDefinitions) {
        return cellDefinitions.stream().filter(k -> k.isGroup())
                .collect(Collectors.toList());
    }

    public List<RowDefinition> getHeads() {
        return heads;
    }

    public List<RowDefinition> getGroupSummary() {
        return groupSummary;
    }

    public void setGroupSummary(List<RowDefinition> groupSummary) {
        this.groupSummary = groupSummary;
    }

    public boolean haveSummary() {
        return IteratorUtil.isNotEmpty(this.getSummary());
    }

    public boolean haveTitle() {
        return IteratorUtil.isNotEmpty(this.getTitle());
    }

    public boolean haveHead() {
        return IteratorUtil.isNotEmpty(this.getHeads());
    }

    public boolean haveGroupSummary() {
        return IteratorUtil.isNotEmpty(this.getGroupSummary());
    }

    public boolean haveElements() {
        return IteratorUtil.isNotEmpty(this.getElements());
    }

    public boolean haveGroup() {
        return IteratorUtil.isNotEmpty(this.getElements()) && this.getElements().stream().anyMatch(k -> k.haveGroup());
    }

    public int getTitleHeight() {
        int titleHeight = 0;
        for (RowDefinition rowDefinition : this.title) {
            titleHeight = titleHeight + rowDefinition.getHeight();
        }
        return titleHeight;
    }

    public int getHeadHeight() {
        int headHeight = 0;
        for (RowDefinition rowDefinition : this.heads) {
            headHeight = headHeight + rowDefinition.getHeight();
        }
        return headHeight;
    }

    public boolean isLoopPrintTitle() {
        return loopPrintTitle;
    }

    public void setLoopPrintTitle(boolean loopPrintTitle) {
        this.loopPrintTitle = loopPrintTitle;
    }

    public boolean isLoopPrintHead() {
        return loopPrintHead;
    }

    public void setLoopPrintHead(boolean loopPrintHead) {
        this.loopPrintHead = loopPrintHead;
    }

    public boolean isIgnorePagination() {
        return ignorePagination;
    }

    public void setIgnorePagination(boolean ignorePagination) {
        this.ignorePagination = ignorePagination;
    }

    public Form getQueryForm() {
        return queryForm;
    }

    public void setQueryForm(Form queryForm) {
        this.queryForm = queryForm;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }


    public FormItem findFormItem(String itemId) {
        if (queryForm == null) {
            return null;
        }
        List<List<FormItem>> group = queryForm.getGroup();
        if (IteratorUtil.isEmpty(group)) {
            return null;
        }
        for (List<FormItem> row : group) {
            for (FormItem item : row) {
                if (item.getId().equals(itemId)) {
                    return item;
                }
            }
        }
        return null;
    }
}